/* 块状链表
* 1.解题思路 懒标记
    add:本段中的所有数都要加上add
    sum:本段的真实和是多少(算上add)

* 2.op
    -□-□-□-□-□-□-□-
    插入：
        分裂节点 O(sqrt(n))
        在分裂点插入序列 O(sqrt(n))

    删除：
        删除开头节点的后半部分 O(sqrt(n))
        删除中间完整节点 O(sqrt(n))
        删除结尾节点的前半部分

    合并:
        遍历整个链表，若下一个点可以合并当前点，则合并

*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <cstdio>
#include <cstring>
using namespace std;
const int N=2000, M=2010;

struct node { //链表单节点
    char s[N+1]; //块内连续字符串
    int size, l, r; //字符串长度 左节点 右节点
}link[M]; //链表

int n, block, in; //操作数 光标在第几块 块内第几个字符后边
char str[20000010];
int q[M], stktop; //内存回收机制

inline void printcursor()
{
    printf("cursor:[%d, %d]\n", block, in);
}

inline void printnode(int u)
{
    printf("node[%d]: sz:%d l:%d r:%d s:%s\n", u, link[u].size, link[u].l, link[u].r, link[u].s);
}

inline void printsave()
{
    for(int i=stktop+1; i<M; i++)
        printnode(i);
}

void move(int k)//将光标移动到第k个字符后面
{
    block=link[0].r; //从起始节点(前面有个哨兵)开始找第k个字符所在位置
    while(k>link[block].size)  /*printf("[%d, %d] %d\n", block, in, k), */k-=link[block].size, block=link[block].r; //超出当前节点范围，去下个节点寻找
    in=k-1; //块内字符串下标从0开始，第k个字符下表是k-1
}

void add(int pre, int u) //u插入到pre之后
{
    link[u].r=link[pre].r, link[link[u].r].l=u;
    link[pre].r=u, link[u].l=pre;
}

void del(int u) //将节点u删掉
{
    link[link[u].l].r=link[u].r;
    link[link[u].r].l=link[u].l;
    link[u].l=link[u].r=link[u].size=0; //清空u的信息
    q[++stktop]=u; //压入内存回收站
}

void insert(int k) //在光标后面插入k个字符
{
    if(in<link[block].size-1) //光标不在某一块的末尾，则分裂当前块
    {
        int u=q[stktop--]; //拉出一个节点
        for(int i=in+1; i<link[block].size; i++) //分裂出的节点的后半部分复制到新节点中
            link[u].s[link[u].size++]=link[block].s[i]; //新建节点=原节点的字符(复制)
        link[block].size=in+1; //原节点更新长度
        add(block, u); //插入节点
    }

    int cur=block; //记录当前所在节点，每次在当前节点后面插入新的节点
    for(int i=0; i<k;)
    {
        int u=q[stktop--]; //拉出一个节点

        while(link[u].size<N && i<k) //将当前块装满
            link[u].s[link[u].size++]=str[i++];

        add(cur, u); //插入新节点
        cur=u; //修改指针
    }
}

void remove(int k) //将光标后面k个字符删除
{
    if(link[block].size-in-1>=k) //光标和待删除字符全在同一个块内，直接删除
    {
        for(int i=in+k+1, j=in+1; i<link[block].size; i++, j++)
            link[block].s[j]=link[block].s[i];
            link[block].size-=k;
    }
    else //跨块删除
    {
        //1.当前块剩余部分全部删除
        k-=link[block].size-in-1; 
        link[block].size=in+1; //更新长度

        //2.删除中间的整块部分
        while(link[block].r && k>=link[link[block].r].size) 
        {
            k-=link[link[block].r].size;
            del(link[block].r);
        }
        
        //3.删除末尾块的前半部分
        int u=link[block].r;
        for(int i=0, j=k; j<=link[u].size; i++, j++)
            link[u].s[i]=link[u].s[j];
        link[u].size-=k;
    }
}

void get(int k) //输出光标后面k个字符
{
    if(link[block].size-in-1>=k) //光标和待删除字符全在同一个块内，直接输出
        for(int i=in+1; i<=in+k; i++)
            putchar(link[block].s[i]);
    else //跨块输出
    {
        //1.当前块剩余部分全部输出
        k-=link[block].size-in-1; 
        for(int i=in+1; i<link[block].size; i++)
            putchar(link[block].s[i]);   
        
        //2.输出中间的整块部分
        int pre=block;
        while(link[block].r && k>=link[link[block].r].size) 
        {
            int u=link[pre].r;
            for(int i=0; i<link[u].size; i++)
                putchar(link[u].s[i]);
            k-=link[u].size;
            pre=u;
        }
        
        //3.输出末尾块的前半部分
        int u=link[pre].r;
        for(int i=0; i<k; i++)
                putchar(link[u].s[i]);
    }
    puts("");
}

void prev() //将光标前移一个字符
{
    if(!in) //位于当前块开头
    {
        block=link[block].l;
        in=link[block].size-1;
    }
    else in--;
}

void next() //将光标后移一个字符
{
    if(in==link[block].size-1) //位于当前块结尾
    {
        block=link[block].r;
        in=0;
    }
    else in++;
}

void merge()
{
    for(int i=link[0].r; i; i=link[i].r) //枚举每个节点
    {
        while(link[i].r && link[i].size+link[link[i].r].size<N) //存在下一个块 && 当前块和下一块总长未满
        {
            int r=link[i].r;
            for(int j=link[i].size, k=0; k<link[r].size; j++, k++)
                link[i].s[j]=link[r].s[k];
            if(block==r) block=i, in+=link[i].size; //如果光标在被合并块中，当前光标失效，更新光标位置
            link[i].size+=link[r].size; //更新当前节点长度
            del(r); //删除被合并块
        }
    }
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
        freopen("./out.txt","w",stdout);
    #endif

    for(int i=1; i<M; i++) q[++stktop]=i;

    scanf("%d", &n);
    str[0]='*'; //哨兵，处理光标位于左边边界的情况
    insert(1); //插入哨兵
    move(1); //移动光标至哨兵右面
    
    char op[10]; 
    while(n--)
    {
        int k;
        scanf("%s", op);
        if(!strcmp(op, "Move")) //将光标移动到第k个字符后面
        {
            scanf("%d", &k);
            move(k+1); //哨兵+1
        }
        else if(!strcmp(op, "Insert")) //在光标后面插入k个字符
        {
            scanf("%d", &k);
            //接收待插入字符串
            int i=0, cursor=k;
            while(k)
            {
                str[i]=getchar();
                if(str[i]>=32 && str[i]<=126) i++, k--; //只考虑合法字符串
            }
            insert(cursor); //插入
            merge(); //合并较短字符串
        }
        else if(!strcmp(op, "Delete")) //将光标后面k个字符删除
        {
            scanf("%d", &k);
            remove(k);
            merge();
        }
        else if(!strcmp(op, "Get")) //输出光标后面k个字符
        {
            scanf("%d", &k);
            get(k);
        }
        else if(!strcmp(op, "Prev")) prev(); //将光标前移一个字符
        else next(); //将光标后移一个字符
    }
    // printsave();
    return 0;
}